import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QMenu, QAction, QMessageBox,QFileDialog,QDialog,QVBoxLayout,QLabel,QLineEdit,QPushButton,QSplitter,QGroupBox,QTextEdit
from PyQt5 import QtWidgets
from PyQt5.QtCore import Qt, QObject, pyqtSignal
from PyQt5.QtGui import QStandardItemModel, QStandardItem
from xml.etree.ElementTree import Element, SubElement, tostring, ElementTree
import xml.etree.ElementTree as ET
import json
import os

from tools.DButils import DBUtil  # 导入数据库工具类
from forms.ui_mainwindow import Ui_MainWindow  # 导入主界面类
from .dialog_create_project import DialogCreateProject  # 导入创建项目对话框类
from .dialog_config_database import DialogConfigDatabase  # 导入数据库配置对话框类
from .dialog_config_server import DialogConfigServer  # 导入服务器配置对话框类

class NodeEditor(QObject):
    nodeSelected = pyqtSignal(QStandardItem)

    def __init__(self,treeView, sqlQuery, keyFields, excludeFields):
        super().__init__()
        self.sqlQuery = sqlQuery
        self.keyFields = keyFields
        self.excludeFields = excludeFields
        self.treeView = treeView
        self.model = QStandardItemModel()
        self.treeView.setModel(self.model)
        self.treeView.clicked.connect(self.on_node_clicked)

        # 初始化选择节点名称
        self.node_name = ""


    # 节点项目初始化及后续更新
    def load_input_data(self, project_name, node_file, sql_data):
        self.project_name = project_name
        self.node_xml_file = node_file
        self.sql_data = sql_data

        if not self.project_name:
            return
        # 加载 XML 数据
        self.load_model_from_xml()

    def on_node_clicked(self, index):
        node = self.model.itemFromIndex(index)
        if node:
            self.node_name = node.text()
            node_info = self.sql_data.get(self.node_name, {})
            sql_query = node_info.get("sqlQuery","")
            key_fields = node_info.get("keyFields","")
            exclude_fields = node_info.get("excludeFields","")
            self.sqlQuery.setText(sql_query)
            self.keyFields.setText(key_fields)
            self.excludeFields.setText(exclude_fields)

            self.nodeSelected.emit(node)

    def add_node(self, parent_node=None):
        if parent_node is None:
            parent_node = self.model.invisibleRootItem()
        new_node = QStandardItem("新节点")
        parent_node.appendRow(new_node)

    def delete_node(self, node):
        if node and node != self.root_node:
            parent = node.parent() or self.model.invisibleRootItem()
            parent.removeRow(node.row())

    def save_model_to_xml(self):
        def save_node(node, parent_element):
            node_element = SubElement(parent_element, 'node', text=node.text())
            for i in range(node.rowCount()):
                save_node(node.child(i), node_element)

        root = Element('root')
        for i in range(self.root_node.rowCount()):
            save_node(self.root_node.child(i), root)

        tree = ElementTree(root)
        tree.write(self.node_xml_file)

    def load_model_from_xml(self):
        try:
            tree = ET.parse(self.node_xml_file)
            root = tree.getroot()

            def load_node(node_element, parent_item):
                node = QStandardItem(node_element.attrib['text'])
                parent_item.appendRow(node)
                for child_element in node_element:
                    load_node(child_element, node)

            # 清空现有模型
            self.model.removeRows(0, self.model.rowCount()) 

            # 创建一个新的根节点，替代旧的根节点
            self.root_node = QStandardItem(self.project_name)
            self.model.appendRow(self.root_node)

            # 加载XML节点到新的根节点
            for child_element in root:
                load_node(child_element, self.root_node)
        except ET.ParseError:
            QMessageBox.warning(self.treeView, "警告", "文件解析错误，请选择有效的XML文件。")
        except FileNotFoundError:
            QMessageBox.warning(self.treeView, "警告", "文件未找到，请确保文件路径正确。")

    def save_sql_data(self):
        if self.node_name:
            sqlQuery =self.sqlQuery.toPlainText()
            keyFields = self.keyFields.text()
            excludeFields = self.excludeFields.text()
            self.sql_data[self.node_name] = {"sqlQuery": sqlQuery, "keyFields": keyFields, "excludeFields": excludeFields}

        else:
            QMessageBox.warning(self.treeView, "警告", "请先选择节点！")

class MyMainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super(MyMainWindow, self).__init__(parent)
        self.setupUi(self)

        # 读取json项目配置
        self.load_project_config()

        # 加载菜单状态
        self.update_menu_status()
        
        # 设置节点树与内容页面比例
        self.splitter.setStretchFactor(0, 1)
        self.splitter.setStretchFactor(1, 2)

        # treeView
        self.treeView.setContextMenuPolicy(Qt.CustomContextMenu)  # 允许右键菜单
        self.treeView.customContextMenuRequested.connect(self.show_context_menu)

        # 节点编辑器
        self.node_editor = NodeEditor(self.treeView, self.textEdit, self.lineEdit_6, self.lineEdit_7)
        if self.is_file_exist:
            self.node_editor.load_input_data(self.project_name, self.node_xml_file, self.sql_data)

        # 信号与槽关联
        self.action_new.triggered.connect(self.create_new_project)
        self.action_open.triggered.connect(self.open_project)
        self.action_save.triggered.connect(self.save_project)
        self.action_save_as.triggered.connect(self.save_project_as)
        self.action_exit.triggered.connect(self.close)
        self.action_config_database.triggered.connect(self.config_database)
        self.action_config_server.triggered.connect(self.config_server)
        self.action_savesql.triggered.connect(self.save_node_sql_data)
        self.action_connect.triggered.connect(self.connect_database)
        self.action_query.triggered.connect(self.query_database)
        self.action_clear.triggered.connect(self.clear)
        # self.action_sync.triggered.connect(self.sync_database)
        
        # 初始化数据库连接
        self.db = None

    # 连接数据库--ok
    def connect_database(self):
        if self.db_host and self.db_port and self.db_username and self.db_password and self.db_database:
            try:
                self.db = DBUtil(poolname="mypool",poolsize=20,dbhost=self.db_host,dbport=self.db_port,dbuser=self.db_username,dbpassword=self.db_password,dbdatabase=self.db_database)
                self.statusBar().showMessage("数据库连接成功！")
            except Exception as e:
                QMessageBox.warning(self, "警告", f"数据库连接失败！{str(e)}")
        else:
            QMessageBox.warning(self, "警告", "请先配置数据库信息！")

    # 查询数据库
    def query_database(self):
        if self.db:
            sql_query = self.textEdit.toPlainText()
            if sql_query:
                try:
                    result = self.db.select_all(sql_query)
                    if result:
                        self.textEdit_2.setText(str(result))
                    else:
                        self.textEdit_2.setText("查询结果为空！")
                except Exception as e:
                    QMessageBox.warning(self, "警告", f"查询失败！{str(e)}")
            else:
                QMessageBox.warning(self, "警告", "请输入查询语句！")
        else:
            QMessageBox.warning(self, "警告", "请先连接数据库！")

    # 清除文本和查询结果
    def clear(self):
        self.textEdit.clear()
        self.textEdit_2.clear()
        self.lineEdit_6.clear()
        self.lineEdit_7.clear()


    def load_project_config(self):
        with open("config/config.json", "r", encoding="utf-8") as f:
            self.project_data = json.load(f)
        
        self.project_name = self.project_data.get("projectName", "")
        self.project_path = self.project_data.get("projectPath", "")
        self.default_directory = self.project_data.get("defaultDirectory") or os.path.dirname(os.path.dirname(os.path.abspath(__file__)))+"\projects"
        self.is_default = self.project_data.get("isDefault") or False
        self.host = self.project_data.get("host", "")
        self.port = self.project_data.get("port", "")
        self.username = self.project_data.get("username", "")
        self.password = self.project_data.get("password", "")
        self.directory = self.project_data.get("directory", "")

        self.is_file_exist = False  # 项目文件是否存在初始值

        if self.project_name:   # 创建存在时，才判断node_data.xml和sql_data.json文件是否存在，并加载sql_data.json文件
            self.load_sql_data()

        # 打印项目配置信息
        print("project_name:", self.project_name)
        print("project_path:", self.project_path)
        print("default_directory:", self.default_directory)
        print("is_default:", self.is_default)
        print("host:", self.host)
        print("port:", self.port)
        print("username:", self.username)
        print("password:", self.password)
        print("directory:", self.directory)

    def load_sql_data(self):
        self.node_xml_file = self.project_path + "/node_data.xml"
        self.sql_data_file = self.project_path + "/sql_data.json"

        # 判断项目中文件是否存在
        if not os.path.exists(self.node_xml_file) or not os.path.exists(self.sql_data_file):
            QtWidgets.QMessageBox.warning(self, "警告", "项目文件缺失，请检查文件路径是否正确。")
            self.is_file_exist = False
        else:
            self.is_file_exist = True
            # 读取项目中sql_data.json文件中的数据库配置
            with open(self.sql_data_file, "r", encoding="utf-8") as f:
                self.sql_data = json.load(f)
            self.db_host = self.sql_data.get("host", "")
            self.db_port = self.sql_data.get("port", "")
            self.db_username = self.sql_data.get("username", "")
            self.db_password = self.sql_data.get("password", "")
            self.db_database = self.sql_data.get("database", "")

    def show_context_menu(self, position):
        index = self.treeView.indexAt(position)
        if not index.isValid():
            return

        node = self.node_editor.model.itemFromIndex(index)
        menu = QMenu()
        
        # 添加节点动作
        add_action = QAction("添加子节点", self)
        add_action.triggered.connect(lambda: self.node_editor.add_node(node))
        
        # 删除节点动作（根节点不可用）
        del_action = QAction("删除节点", self)
        if node == self.node_editor.root_node:
            del_action.setEnabled(False)
        else:
            del_action.triggered.connect(lambda: self.node_editor.delete_node(node))
        
        menu.addAction(add_action)
        menu.addAction(del_action)
        menu.exec_(self.treeView.viewport().mapToGlobal(position))

    # 创建新项目--ok
    def create_new_project(self):
        create_project_dialog = DialogCreateProject(self, self.default_directory, self.is_default)
        create_project_dialog.create_success_signal.connect(self.update_project_tree)
        create_project_dialog.exec_()

    def open_project(self):
        directory = QFileDialog.getExistingDirectory(self, "选择项目目录")
        if directory:
            self.project_path = directory
            self.load_sql_data()
            if self.is_file_exist:
                self.update_menu_status()
                project_name = os.path.basename(directory)
                self.update_project_tree(project_name, directory, self.default_directory, self.is_default)
                QMessageBox.information(self, "信息", "项目加载成功！")

    def save_project(self):
        if self.project_name:
            self.node_editor.save_model_to_xml() # 保存xml
            with open(self.sql_data_file, "w", encoding="utf-8") as f:
                json.dump(self.sql_data, f, indent=4) # 保存json
            QMessageBox.information(self, "信息", "项目保存成功！")
        else:
            QMessageBox.warning(self, "警告", "请先创建或打开项目！")

    def save_project_as(self):
        if self.project_name:
            create_project_dialog = DialogCreateProject(self, self.project_path, self.is_default, is_save_as=True)
            create_project_dialog.create_success_signal.connect(self.update_project_tree)
            create_project_dialog.exec_()
        else:
            QMessageBox.warning(self, "警告", "请先创建或打开项目！")

    def closeEvent(self, event):
        pass
    
    def save_node_sql_data(self):
        self.node_editor.save_sql_data()

    # 配置数据库--ok
    def config_database(self):
        config_database_dialog = DialogConfigDatabase(self, self.db_host, self.db_port, self.db_username, self.db_password, self.db_database)
        config_database_dialog.signal_config_database.connect(self.update_database_config)
        config_database_dialog.exec_()

    # 配置目标服务器--ok
    def config_server(self):
        config_server_dialog = DialogConfigServer(self,self.host,self.port,self.username,self.password,self.directory)
        config_server_dialog.signal_config_server.connect(self.update_server_config)
        config_server_dialog.exec_()

    # 创建新项目后，更新项目树--ok
    def update_project_tree(self, project_name, project_path, defaultDirectory, is_default):
        print(project_name, project_path, is_default)
        # 更新项目配置
        self.project_name = project_name
        self.project_path = project_path
        self.is_default = is_default
        self.default_directory = defaultDirectory
        self.project_data["projectName"] = project_name
        self.project_data["projectPath"] = project_path
        self.project_data["defaultDirectory"] = defaultDirectory
        self.project_data["isDefault"] = is_default

        # 重新加载配置
        self.node_xml_file = self.project_path + "/node_data.xml"
        self.sql_data_file = self.project_path + "/sql_data.json"
        self.node_editor.load_input_data(project_name, self.node_xml_file, self.sql_data)

        # 更新菜单状态
        self.is_file_exist = True
        self.update_menu_status()

        # 保存到配置文件
        with open("config/config.json", "w", encoding="utf-8") as f:
            json.dump(self.project_data, f, indent=4)

    # 数据库配置更新后，更新数据库配置
    def update_database_config(self, host, port, username, password, database):
        self.db_host = host
        self.db_port = port
        self.db_username = username
        self.db_password = password
        self.db_database = database
        
        # 存入到项目的json配置文件中
        self.sql_data["host"] = host
        self.sql_data["port"] = port
        self.sql_data["username"] = username
        self.sql_data["password"] = password
        self.sql_data["database"] = database
        with open(self.sql_data_file, "w", encoding="utf-8") as f:
            json.dump(self.sql_data, f, indent=4)
    
    # 服务器配置更新后，更新服务器配置--ok
    def update_server_config(self,host,port,username,password,directory):
        self.host = host
        self.port = port
        self.username = username
        self.password = password
        self.directory = directory
        # 存入到项目的json配置文件中
        self.project_data["host"] = host
        self.project_data["port"] = port
        self.project_data["username"] = username
        self.project_data["password"] = password
        self.project_data["directory"] = directory
        with open("config/config.json", "w", encoding="utf-8") as f:
            json.dump(self.project_data, f, indent=4)

    # 未新建或打开项目时，禁用菜单栏,打开后启用菜单栏，只有新建和打开不受影响---ok
    def update_menu_status(self):
        if self.project_name and self.is_file_exist:
            self.action_save.setEnabled(True)
            self.action_save_as.setEnabled(True)
            self.action_config_database.setEnabled(True)
            self.action_config_server.setEnabled(True)
        else:
            self.action_save.setEnabled(False)
            self.action_save_as.setEnabled(False)
            self.action_config_database.setEnabled(False)
            self.action_config_server.setEnabled(False)